/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package tresenraya;

/**
 *
 * @author Helena
 */

import static utilidades.constantes.*;

public class Posicion implements Cloneable {
    private Casilla [][] tablero;
    Jugador [] jugadores;
    private int turno;
    private VisualizadorDePosicion visualizador;
    int [] fichasPuestas;

    public Posicion(Jugador jugador1, Jugador jugador2, int turno)
    {
        construccionBasica(jugador1, jugador2, turno);
        visualizador = new VisualizadorDePosicionTUI(this);
    }

    void construccionBasica(Jugador jugador1, Jugador jugador2, int turno)
    {
        this.jugadores = new Jugador[2];
        this.jugadores[0] = jugador1;
        this.turno = turno;
        this.jugadores[1] = jugador2;
        fichasPuestas = new int[2];
        fichasPuestas[0] = 0;
        fichasPuestas[1] = 1;
        tablero = new Casilla[3][3];

        for(int i = 0; i < 3; i++)
            for(int j = 0; j < 3; j++)
            {
                tablero[i][j] = Casilla.VACIA;
            }

        fichasPuestas[0] = 0;
        fichasPuestas[1] = 0;
    }

    @Override
    public Posicion clone()
    {
        Posicion posicion = null;
        try
        {
            posicion = (Posicion) super.clone();
        }catch(CloneNotSupportedException ex){
            System.out.println(" no se puede duplicar la posición");
            return null;
        }

        posicion.tablero=(Casilla[][])this.getTablero().clone();
        for(int i=0; i<this.getTablero().length; i++){
            posicion.tablero[i]=(Casilla[])this.getTablero()[i].clone();
        }
        posicion.fichasPuestas=(int [])this.fichasPuestas.clone();

        return posicion;
    }

    public int lineasDominadas(Jugador jugador)
    {
        int nLineasDominadas = 0;

        for(int i = 0; i < 3; i++)
        {
            Iterador<Casilla> iteradorFila = new IteradorFila(getTablero(),i);
            if (dominaLinea(jugador, iteradorFila))
            {
                nLineasDominadas++;
            }
        }
        for(int i = 0; i < 3; i++)
        {
            Iterador iteradorColumna = new IteradorColumna(getTablero(),i);
            if (dominaLinea(jugador, iteradorColumna))
            {
                nLineasDominadas++;
            }
        }
        Iterador iteradorDiagIzqDra = new IteradorDiagIzqDra(getTablero());
        if (dominaLinea(jugador, iteradorDiagIzqDra))
        {
            nLineasDominadas++;
        }

        Iterador iteradorDiagDraIzq = new IteradorDiagDraIzq(getTablero());

        if (dominaLinea(jugador, iteradorDiagDraIzq))
        {
            nLineasDominadas++;
        }

        return nLineasDominadas;
    }

    public boolean dominaLinea(Jugador jugador, Iterador<Casilla> iterador)
    {
        Casilla tipoCasillaJugador = obtenerTipoCasillaDeJugador(jugador);
        Casilla tipoCasillaContrario = obtenerTipoCasillaDeContrario(jugador);

        boolean hayFichaJugador = false, hayFichaContrario = false;

        while (iterador.haySiguiente() && !hayFichaContrario)
        {
            Casilla casillaEncontrada = iterador.obtenerSiguiente();
            hayFichaJugador = hayFichaJugador || (casillaEncontrada == tipoCasillaJugador);
            hayFichaContrario = hayFichaContrario || (casillaEncontrada == tipoCasillaContrario);
        }

        return hayFichaJugador && !hayFichaContrario;
    }

    boolean hayTresEnRaya(Jugador jugador)
    {
        boolean hayTresEnRaya = false;

        for(int i = 0; i < 3 && !hayTresEnRaya; i++)
        {
            Iterador iteradorFila = new IteradorFila(getTablero(),i);
            hayTresEnRaya = hayTresEnRaya || hayTresEnRayaEnUnaLinea(jugador, iteradorFila);
        }
        for(int i = 0; i < 3 && !hayTresEnRaya; i++)
        {
            Iterador iteradorColumna = new IteradorColumna(getTablero(),i);
            hayTresEnRaya = hayTresEnRaya || hayTresEnRayaEnUnaLinea(jugador, iteradorColumna);
        }

        Iterador iteradorDiagIzqDra = new IteradorDiagIzqDra(getTablero());
        hayTresEnRaya = hayTresEnRaya || hayTresEnRayaEnUnaLinea(jugador, iteradorDiagIzqDra);

        Iterador iteradorDiagDraIzq = new IteradorDiagDraIzq(getTablero());

        hayTresEnRaya = hayTresEnRaya ||hayTresEnRayaEnUnaLinea(jugador, iteradorDiagDraIzq);

        return hayTresEnRaya;
    }

    public boolean hayTresEnRayaEnUnaLinea(Jugador jugador, Iterador<Casilla> iterador)
    {
        Casilla tipoCasillaJugador = obtenerTipoCasillaDeJugador(jugador);

        int nFichasJugador = 0;
        boolean hayFichaJugador;

        do
        {
            Casilla casillaEncontrada = iterador.obtenerSiguiente();
            hayFichaJugador = (casillaEncontrada == tipoCasillaJugador);
            if (hayFichaJugador) nFichasJugador++;
        }while (iterador.haySiguiente() && hayFichaJugador);

        return nFichasJugador == 3;
    }

    public Casilla obtenerTipoCasillaDeJugador(Jugador jugador)
    {
        if (jugador.getClass().getName().contains("JugadorHumano"))
            return Casilla.JUGADOR_1;
        else return Casilla.JUGADOR_2;
    }

    public Casilla obtenerTipoCasillaDeContrario(Jugador jugador)
    {
        if (jugador.getClass().getName().contains("JugadorHumano"))
            return Casilla.JUGADOR_2;
        else return Casilla.JUGADOR_1;
    }

    public int faseActual()
    {
        if (fichasPuestas[getTurno()] == 3) return MOVER;
        else return PONER;
    }

    public boolean preCondicionPonerFicha(int fila, int columna)
    {
        return (!hayTresEnRaya(jugadores[0]) &&
                !hayTresEnRaya(jugadores[1]) &&
                faseActual() == PONER && getTablero()[fila][columna] == Casilla.VACIA);
    }

    public void ponerFicha(int fila, int columna)
    {
        tablero[fila][columna] = obtenerTipoCasillaDeJugador(jugadores[getTurno()]);
        fichasPuestas[getTurno()]++;
        turno = (++turno) % 2;
    }

    public boolean preCondicionMoverFicha(int filaOrigen, int columnaOrigen,
                              int filaDestino, int columnaDestino)
    {
        return (!hayTresEnRaya(jugadores[0]) &&
                !hayTresEnRaya(jugadores[1]) &&
                faseActual() == MOVER &&
                getTablero()[filaOrigen][columnaOrigen] == obtenerTipoCasillaDeJugador(jugadores[getTurno()]) &&
                getTablero()[filaDestino][columnaDestino] == Casilla.VACIA);

    }

    public void moverFicha(int filaOrigen, int columnaOrigen,
                              int filaDestino, int columnaDestino)
    {
       tablero[filaOrigen][columnaOrigen] = Casilla.VACIA;
       tablero[filaDestino][columnaDestino] = obtenerTipoCasillaDeJugador(jugadores[getTurno()]);
       turno = (++turno) % 2;
    }

    /**
     * @return the visualizador
     */
    public VisualizadorDePosicion getVisualizador() {
        return visualizador;
    }

    /**
     * @return the turno
     */
    public int getTurno() {
        return turno;
    }

    /**
     * @return the tablero
     */
    public Casilla[][] getTablero() {
        return tablero;
    }
}

